# 导入相关库和模块
from contextlib import contextmanager
from typing import Union, Dict
from database import SessionLocal
import asyncio
from sqlalchemy.orm import sessionmaker
from config.logging import logger
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from services.database_manager import databaseManager
from models.sys_roles import SysRole, SysRoleSchema
from sqlalchemy.exc import SQLAlchemyError
from models.sys_role_menus import SysRoleMenu
from models.admin_menu import AdminMenu
from config.mysql_settings import AIO_DATABASE_URL, DATABASE_URL
engine = create_async_engine(AIO_DATABASE_URL, echo=True)
from sqlalchemy import create_engine


sync_engine = create_engine(DATABASE_URL, echo=True)
SyncSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=sync_engine)

# 使用 sessionmaker 创建异步会话
AsyncSessionLocal = sessionmaker(
    bind=engine,
    class_=AsyncSession,
    expire_on_commit=False
)
# 定义服务类
class SysRoleApiService:
    def __init__(self, db):
        self.db = db
        self.db_manager = databaseManager(self.db)

    async def lists(self, page: int, limit: int, roleName: str) -> dict:
        """
        角色列表
        """
        query = self.db.query(SysRole)
        if roleName:
            query = query.filter(SysRole.role_name == roleName)
        lists = self.db_manager.paginate_query(query, page, limit)
        total_count = query.count()
        res = [SysRoleSchema.from_orm(info).dict() for info in lists]
        return {"list": self.db_manager.convert_dict_keys(res), 'total': total_count}


    async def create(self, roleData: dict, userId) -> dict:
        """
        创建角色
        """
        roleInfo = self.db_manager.snake_convert_dict_keys({
            "roleName": roleData["roleName"],
            "roleKey": roleData["roleKey"],
            "roleSort": roleData["roleSort"],
            "status": roleData["status"],
            "remark": roleData["remark"],
            "menuCheckStrictly": roleData["menuCheckStrictly"],
            "deptCheckStrictly": roleData["deptCheckStrictly"],
            "createBy": userId,
            "updateBy": userId
        })
        logger.info(f"创建角色{roleInfo}")
        menuIds_str = roleData.get("menuIds", "")
        menuIds = [int(id_str.strip()) for id_str in menuIds_str.split(",")]

        # 检查角色名称是否存在
        sameRole = self.db_manager.detail_query(SysRole, {"role_name": roleInfo["role_name"]}, need=True)
        if sameRole:
            logger.debug(f"角色名称已存在: {sameRole}")
            return {"error": "角色名称已存在"}

            # 验证所有的 menuIds 是否在 admin_menu 表中存在
        for menu_id in menuIds:
            exists = self.db_manager.detail_query(AdminMenu, {"id": menu_id}, need=True)
            if not exists:
                logger.debug(f"菜单ID {menu_id} 不存在")
                return {"error": f"菜单ID {menu_id} 不存在"}
                # 创建角色
        new_role = self.db_manager.create_entry(SysRole, roleInfo)
        if not new_role:
            logger.debug("角色创建失败，数据库操作未成功")
            return {"error": "角色创建失败，数据库操作未成功"}

        async with AsyncSessionLocal() as session:
            self.db_manager.db = session
            async with session.begin():
                try:
                    # 获取新创建角色的 ID
                    new_role_id = new_role["id"]
                    if not new_role_id:
                        logger.debug("角色创建失败，无法获取新角色ID")
                        return {"error": "角色创建失败，无法获取新角色ID"}

                    # 写入 role_menu 表 menuIds
                    for menu_id in menuIds:
                        role_menu = SysRoleMenu(role_id=new_role_id, menu_id=menu_id)
                        session.add(role_menu)
                        logger.info(f"已将菜单 {menu_id} 添加到角色 {new_role_id}")

                    # 提交事务
                    await session.commit()

                    return new_role

                except SQLAlchemyError as e:
                    await session.rollback()
                    logger.error(f"角色创建失败，数据库操作出错: {str(e)}")
                    return {"error": f"角色创建失败，数据库操作出错: {str(e)}"}

    async def update(self, roleId: int, roleData: dict, userId: str) -> dict:
        """
        更新角色
        """
        roleInfo = self.db_manager.snake_convert_dict_keys({
            "roleName": roleData["roleName"],
            "roleKey": roleData["roleKey"],
            "roleSort": roleData["roleSort"],
            "status": roleData["status"],
            "remark": roleData["remark"],
            "menuCheckStrictly": roleData["menuCheckStrictly"],
            "deptCheckStrictly": roleData["deptCheckStrictly"],
            "updateBy": userId
        })
        logger.info(f"更新角色{roleInfo}")
        menuIds_str = roleData.get("menuIds", "")
        menuIds = [int(id_str.strip()) for id_str in menuIds_str.split(",")]

        async with AsyncSessionLocal() as session:
            self.db_manager.db = session
            async with session.begin():
                try:
                    # 检查角色是否存在
                    existingRole = await self.db_manager.async_detail_query(SysRole, {"id": roleId}, need=True)
                    if not existingRole:
                        logger.debug(f"角色ID不存在: {roleId}")
                        return {"error": "角色ID不存在"}

                    # 检查角色名称是否已经存在且不是当前角色
                    sameRole = await self.db_manager.async_detail_query(SysRole, {"role_name": roleInfo["role_name"]}, need=True)
                    if sameRole and sameRole["id"] != roleId:
                        logger.debug(f"角色名称已存在: {sameRole}")
                        return {"error": "角色名称已存在"}

                    # 验证所有的 menuIds 是否在 admin_menu 表中存在
                    for menu_id in menuIds:
                        exists = await self.db_manager.async_detail_query(AdminMenu, {"id": menu_id}, need=True)
                        if not exists:
                            logger.debug(f"菜单ID {menu_id} 不存在")
                            return {"error": f"菜单ID {menu_id} 不存在"}

                    # 使用同步的Session进行数据库操作
                    updated_role = await asyncio.get_event_loop().run_in_executor(None, self._sync_detail_update, SysRole, {"id": roleId}, roleInfo)
                    if not updated_role:
                        logger.debug("角色更新失败，数据库操作未成功")
                        return {"error": "角色更新失败，数据库操作未成功"}

                    # 删除旧的角色菜单关联
                    delete_result = await asyncio.get_event_loop().run_in_executor(None, self._sync_delete_records_by_ids, SysRoleMenu, {"role_id": roleId})
                    if not delete_result:
                        logger.debug("删除旧的角色菜单关联失败")
                        return {"error": "删除旧的角色菜单关联失败"}

                    # 写入 role_menu 表 menuIds
                    for menu_id in menuIds:
                        role_menu = SysRoleMenu(role_id=roleId, menu_id=menu_id)
                        session.add(role_menu)
                        logger.info(f"已将菜单 {menu_id} 添加到角色 {roleId}")

                    # 提交事务
                    await session.commit()

                    return updated_role

                except SQLAlchemyError as e:
                    await session.rollback()
                    logger.error(f"角色更新失败，数据库操作出错: {str(e)}")
                    return {"error": f"角色更新失败，数据库操作出错: {str(e)}"}

    async def detail(self, roleId: int) -> dict:
        """
        获取角色详细信息
        """
        async with AsyncSessionLocal() as session:
            self.db_manager.db = session
            async with session.begin():
                try:
                    # 获取角色基本信息
                    role_info = await self.db_manager.async_detail_query(SysRole, {"id": roleId}, need=True)
                    if not role_info:
                        logger.debug(f"角色ID不存在: {roleId}")
                        return {"error": "角色ID不存在"}

                    # 获取角色的菜单关联信息
                    role_menus = await self.db_manager.async_list_query(SysRoleMenu, {"role_id": roleId}, needRow=True)
                    menu_ids = [role_menu.menu_id for role_menu in role_menus]

                    # 组合返回数据
                    role_detail = role_info
                    role_detail["menu_ids"] = menu_ids

                    return self.db_manager.convert_dict_keys(role_detail)

                except SQLAlchemyError as e:
                    logger.error(f"获取角色详细信息失败，数据库操作出错: {str(e)}")
                    return {"error": f"获取角色详细信息失败，数据库操作出错: {str(e)}"}

    async def delete(self, roleId: int) -> Union[Dict[str, str],bool]:
        """
        删除角色及其关联的菜单记录
        """
        async with AsyncSessionLocal() as session:
            self.db_manager.db = session
            async with session.begin():
                try:
                    # 检查角色是否存在
                    existingRole = await self.db_manager.async_detail_query(SysRole, {"id": roleId}, need=True)
                    if not existingRole:
                        logger.debug(f"角色ID不存在: {roleId}")
                        return {"error": "角色ID不存在"}

                    # 删除角色菜单关联
                    delete_role_menu_result = await asyncio.get_event_loop().run_in_executor(
                        None, self._sync_delete_records_by_role_id, SysRoleMenu, {"role_id": roleId})
                    if not delete_role_menu_result:
                        logger.debug("删除旧的角色菜单关联失败")
                        return {"error": "删除旧的角色菜单关联失败"}

                    # 删除角色
                    delete_role_result = await asyncio.get_event_loop().run_in_executor(
                        None, self._sync_delete_records_by_id, SysRole, roleId)
                    if not delete_role_result:
                        logger.debug("删除角色失败")
                        return {"error": "删除角色失败"}

                    # 提交事务
                    await session.commit()

                    return True

                except SQLAlchemyError as e:
                    await session.rollback()
                    logger.error(f"角色删除失败，数据库操作出错: {str(e)}")
                    return {"error": f"角色删除失败，数据库操作出错: {str(e)}"}

    def _sync_delete_records_by_role_id(self, model, conditions):
        """
        同步删除数据库记录
        """
        with SyncSessionLocal() as session:
            self.db_manager.db = session
            return self.db_manager.delete_records_by_conditions(model, conditions)

    def _sync_delete_records_by_id(self, model, roleId):
        """
        同步删除数据库记录
        """
        with SyncSessionLocal() as session:
            self.db_manager.db = session
            return self.db_manager.delete_records_by_ids(model, [roleId])

    def _sync_detail_update(self, model, param, content):
        """
        同步更新数据库记录
        """
        with SyncSessionLocal() as session:
            self.db_manager.db = session
            return self.db_manager.detail_update(model, param, content)

    def _sync_delete_records_by_ids(self, model, param):
        """
        同步删除数据库记录
        """
        with SyncSessionLocal() as session:
            self.db_manager.db = session
            return self.db_manager.delete_records_by_conditions(model, param)
